<?php
/**
 *  Naneau_Validator_Abstract
 * 
 * @category   Naneau
 * @package    Naneau_Validator
 * @copyright  Copyright (c) 2007 Maurice Fonk - http://naneau.nl
 * @version    0.1
 */

/**
 * Validator abstract class
 *
 * abstract class for validating user input
 *
 * @category   Naneau
 * @package    Naneau_Validator
 * @copyright  Copyright (c) 2007 Maurice Fonk - http://naneau.nl
 */
abstract class Naneau_Validator_Abstract {

    /**
     * array of validators
     * 
     * in form [field] => array(array(validator, message))
     *
     * @var array
     */
    private $_fieldValidators = array();

    /**
     * validators for all values
     *
     * @var array
     */
    private $_allValidators = array();

    /**
     * required fields
     *
     * @var array
     */
    private $_required = array();

    /**
     * array of error messages
     *
     * @var array
     */
    private $_messages = array();

    /**
     * name for default errors
     *
     * @var string
     */
    protected $_defaultName = 'default';

    /**
     * add a validator to the chain
     *
     * @param string $field the field to apply it to
     * @param Zend_Validate $validator
     * @param string $message the message to display when validation fails
     * @return void
     */
    protected function addFieldValidator($field, $validator, $message) {
        $this->_fieldValidators[$field][] = array($validator, $message);
    }

    /**
     * add validator that operates on ALL values
     *
     * @param Zend_Validate $validator
     * @param string $message the message to display when validation fails
     * @return void
     */
    protected function addAllValidator($validator, $message) {
        $this->_allValidators[] = array($validator, $message);
    }

    /**
     * set a required field
     *
     * @param string $field the required field
     * @param string $message the message to display if the field is absent
     */
    public function setRequired($field, $message) {
        $this->_required[$field] = $message;
    }

    /**
     * get error messages after validation failed
     * 
     * array in form: [$field] = array('message1', 'message2');
     *
     * @return array
     */
    public function getMessages() {
        return $this->_messages;
    }

    /**
     * validate an array of values
     * 
     * @see getMessages()
     *
     * @param array $array values
     * @return bool $valid true on success
     */
    public function validateArray($values) {

        foreach ($this->_required as $field => $message) {
            if (!isset($values[$field]) || empty($values[$field])) {
                $this->_messages[$field][] = $message;
            }
        }
        //check required fields

        foreach ($this->_fieldValidators as $field => $validators) {

            if (!isset($this->_required[$field]) && empty($values[$field])) {
                continue;
                //don't check empty non-required fields
            }
            
            if (isset($values[$field])) {
                //the field exists
                foreach ($validators as $val) {
                    //all validators for $field
                    if (!$val[0]->isValid($values[$field])) {
                        //validator failed for $field
                        $this->_messages[$field][] = $val[1];
                    }
                }
            }
        }
        //apply validators

        foreach ($this->_allValidators as $val) {
            if (!$val[0]->isValid($values)) {
                //validator failed for $field
                $this->_messages[$this->_defaultName][] = $val[1];
            }
        }
        //check all

        return (count($this->_messages) == 0);
    }

    /**
     * validate a single field
     *
     * @see getMessages()
     *
     * @param array $array values
     * @param string $field the field to validate
     * @return bool $valid true on success
     */
    public function validateField($values, $field) {
        if (isset($this->_required[$field]) && !isset($values[$field])) {
            $this->_messages[] = $this->_required[$field];
        }
        //check required

        if (isset($this->_fieldValidators[$field])) {
            //there are validators for the field

            if (!isset($this->_required[$field]) && empty($values[$field])) {
                break;
                //don't check empty non-required fields
            }

            foreach ($this->_fieldValidators[$field] as $val) {
                //all validators for $field
                if (!$val[0]->isValid($values[$field])) {
                    //validator failed for $field
                    $this->_messages[$field][] = $val[1];
                }
            }

        }
        //apply validators

        return (count($this->_messages) == 0);
    }

}